import {Api} from '@/api/type'
import {DataTableBaseColumn, PaginationProps} from 'naive-ui'
import {TableColumn} from 'naive-ui/es/data-table/src/interface'
import {computed, ComputedRef, reactive, ref, Ref, UnwrapNestedRefs} from 'vue'

export type R<R> = Api.Common.R<R>;
export type PageInfo = Api.Common.PageInfo;
export type PageRecord<T> = Api.Common.PageRecord<T>;
export type TableDataWithIndex<T> = T & {index: number};
export type TransformData<T> = {
    list: TableDataWithIndex<T>[];
    page: number;
    size: number;
    total: number;
};
export type Transformer<T> = (response: R<PageRecord<T> | Array<T>>) => TransformData<T>;
export type TableConfig<T, C extends TableColumn<T>> = {
    queryFn: (query: any) => Promise<R<PageRecord<T> | Array<T>>>;
    columnList: () => Array<C>;
    queryParameter?: Partial<T>;
    transformer?: Transformer<T>;
    pageParameter?: Pick<PageInfo, 'page' | 'size'>;
};
export type TableColumnSelect = {
    key: string | number;
    title: string;
    select: boolean;
};

const expandKey: string = 'expandKey'
const selectionKey: string = 'selectionKey'

export function useTable<T, C extends TableColumn<T>>(config: TableConfig<T, C>) {
    // 选中的行的ID
    const keyList: Ref<string[]> = ref<string[]>([])
    // 是否正在加载
    let loading: Ref<boolean> = ref<boolean>(false)
    // 查询参数
    const queryParameter: UnwrapNestedRefs<Partial<T>> = reactive({...(config.queryParameter || {} as Partial<T>)})
    // 分页参数
    const pageParameter: Pick<PageInfo, 'page' | 'size'> = config.pageParameter || {page: 1, size: 10}
    // 从接口获取到的数据
    const data: Ref<T[]> = ref([])
    // 所有的表头
    const allColumn: Ref<Array<C>> = ref(config.columnList() || []) as Ref<Array<C>>
    // 选中的表头列表
    const selectList: Ref<Array<TableColumnSelect>> = ref(getColumnSelectList(config.columnList()))
    //
    const columnList: ComputedRef<C[]> = computed(() => reloadColumnList(allColumn.value, selectList.value))

    // 分页配置
    const pagination: PaginationProps = reactive({
        page: pageParameter.page,
        pageSize: pageParameter.size,
        itemCount: 0,
        showSizePicker: true,
        pageSizes: [10, 20, 50],
        onUpdatePage: async (page: number) => {
            updatePagination({page: page})
            await getData()
        },
        onUpdatePageSize: async (size: number) => {
            updatePagination({page: 1, pageSize: size})
            await getData()
        }
    })

    function updateParameter(parameter: Partial<T> | Pick<PageInfo, 'page' | 'size'>) {
        Object.assign(queryParameter, parameter)
    }

    function updatePagination(update: Partial<PaginationProps>) {
        Object.assign(pagination, update)
    }

    function formatQueryParameter(parameter: Record<string, any>) {
        const _parameter: Record<string, any> = {}
        Object.entries(parameter).forEach(([key, value]) => {
            if (value != null && String(value) != '') {
                _parameter[key] = value
            }
        })
        _parameter.page = pagination.page
        _parameter.size = pagination.pageSize

        return _parameter
    }

    function transformer(response: R<PageRecord<T> | Array<T>>): TransformData<T> {
        let list: Array<T>
        let page: number
        let size: number
        let total: number

        if (response.data instanceof Array) {
            list = response.data || []
            page = 1
            size = 10
            total = list.length
        } else {
            list = response?.data?.list || []
            page = response?.data?.page || 1
            size = response?.data?.size || 10
            total = response?.data?.total || 0
        }
        const dataWithIndex = list.map((item: T, index: number) => {
            return {...item, index: (page - 1) * size + index + 1}
        })
        return {
            list: dataWithIndex,
            page: page,
            size: size,
            total: total
        }
    }

    function resetParameter() {
        Object.assign(queryParameter, {...config.queryParameter})
        updatePagination({
            page: pageParameter.page,
            pageSize: pageParameter.size,
            itemCount: 0
        })
    }

    async function getData() {
        loading.value = true
        let parameter: Record<string, any> = formatQueryParameter(queryParameter)
        const response: R<PageRecord<T> | Array<T>> = await config.queryFn(parameter)
        const transformData: TransformData<T> = config.transformer ? config.transformer(response) : transformer(response)
        const list: TableDataWithIndex<T>[] = transformData.list
        data.value = list || []

        // 判断返回的是分页对象还是数组对象
        if (response.data instanceof Array) {
            updatePagination({
                page: Number(1),
                pageSize: Number(10),
                itemCount: Number(response.data.length)
            })
        } else {
            updatePagination({
                page: Number(response.data?.page || 1),
                pageSize: Number(response.data?.size || 10),
                itemCount: Number(response.data?.total || 0)
            })
        }
        //初始化选中行key数组
        keyList.value = []
        loading.value = false
    }

    function reloadColumnList(columnList: Array<C>, selectList: Array<TableColumnSelect>): Array<C> {
        const columnMapping: Map<string, C> = new Map<string, C>()
        columnList.forEach(column => {
            if (columnHasKey<T>(column)) {
                let key = (column as DataTableBaseColumn).key
                columnMapping.set(String(key), column)
            }
            if (column.type === 'selection') {
                column = {...column, title: '选择行'}
                columnMapping.set(selectionKey, column)
            }
            if (column.type === 'expand') {
                column = {...column, title: '折叠行'}
                columnMapping.set(expandKey, column)
            }
        })

        let list: Array<C> = []
        selectList.forEach((item) => {
            let column = columnMapping.get(String(item.key))
            if (item.select && column) {
                list.push(column)
            }
        })
        return list
    }

    function getColumnSelectList(columnList: Array<C>): Array<TableColumnSelect> {
        const selectList: Array<TableColumnSelect> = []
        columnList.forEach(column => {
            let data: TableColumnSelect = {
                key: '',
                title: '',
                select: true
            }
            if (columnHasKey<T>(column)) {
                data.key = (column as DataTableBaseColumn).key
                data.title = (column as DataTableBaseColumn).title as string
            }
            if (column.type == 'selection') {
                data.key = selectionKey
                data.title = '选择列'
            }
            if (column.type == 'expand') {
                data.key = expandKey
                data.title = '展开列'
            }
            selectList.push(data)
        })
        return selectList
    }

    getData()

    return {
        data,
        loading,
        pagination,
        columnList,
        selectList,
        getData,
        keyList,
        queryParameter,
        resetParameter,
        updateParameter,
        updatePagination,
        reloadColumnList
    }
}

export function useTableOperate<T>(getData: () => Promise<void>) {
    const rowKeyList: Ref<Array<string>> = ref<string[]>([])

    async function onBatchDelete() {
        rowKeyList.value = []
        await getData()
    }

    async function onDelete() {
        await getData()
    }

    return {
        rowKeyList,
        onBatchDelete,
        onDelete
    }
}

function columnHasKey<T>(column: TableColumn<T>): boolean {
    return Boolean((column as DataTableBaseColumn).key)
}
